
//
// Created by wxd on 2025/7/28.
//
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "GameFPSCameraControl.h"
#include <glm/glm.hpp>

void GameFPSCameraControl::setSpeed(const float speed) {
    m_CameraMoveSpeed = speed;
}

void GameFPSCameraControl::setSensitivity(const float sensitivity) {
    m_MouseSensitivity = sensitivity;
}

void GameFPSCameraControl::setMaxPitch(const float maxPitch) {
    m_MaxPitch = maxPitch;
}

void GameFPSCameraControl::setMinPitch(const float minPitch) {
    m_MinPitch = minPitch;
}

void GameFPSCameraControl::setPitchRange(const float maxPitch, const float minPitch) {
    m_MaxPitch = maxPitch;
    m_MinPitch = minPitch;
}

float GameFPSCameraControl::getSpeed() const {
    return m_CameraMoveSpeed;
}

float GameFPSCameraControl::getMaxPitch() const {
    return m_MaxPitch;
}

float GameFPSCameraControl::getMinPitch() const {
    return m_MinPitch;
}

float GameFPSCameraControl::getSensitivity() const {
    return m_MouseSensitivity;
}

bool GameFPSCameraControl::isBetweenPitchRange(float curPitch) const {
    return curPitch >= m_MinPitch && curPitch <= m_MaxPitch;
}

void GameFPSCameraControl::setMouseCenter(const float windowWidth, const float windowHeight) {
    m_MouseStatus.curMousePosX = windowWidth * 0.5f;
    m_MouseStatus.curMousePosY = windowHeight * 0.5f;
}

bool GameFPSCameraControl::isLeftMove() {
    const bool flag = m_KeyBoardMap[GLFW_KEY_A];
    if (flag) {
        m_CameraMoveType = CameraMoveType::LEFT;
    }
    return flag;
}

bool GameFPSCameraControl::isRightMove() {
    const bool flag = m_KeyBoardMap[GLFW_KEY_D];
    if (flag) {
        m_CameraMoveType = CameraMoveType::RIGHT;
    }
    return flag;
}

bool GameFPSCameraControl::isBackMove() {
    const bool flag = m_KeyBoardMap[GLFW_KEY_S];
    if (flag) {
        m_CameraMoveType = CameraMoveType::BACK;
    }
    return flag;
}

bool GameFPSCameraControl::isForwardMove() {
    const bool flag = m_KeyBoardMap[GLFW_KEY_W];
    if (flag) {
        m_CameraMoveType = CameraMoveType::FORWARD;
    }
    return flag;
}

// 更新键盘按键事件到缓存中
void GameFPSCameraControl::onKeyBoard(int key, int action, int mods) {
    BaseCameraControl::onKeyBoard(key, action, mods);
}

void GameFPSCameraControl::onCursor(float xpos, float ypos) {
    float dYaw = static_cast<float>(xpos - m_MouseStatus.curMousePosX) * m_MouseSensitivity;
    float dPitch = static_cast<float>(ypos - m_MouseStatus.curMousePosY) * m_MouseSensitivity;
    onCameraGazeEvent(dPitch, dYaw);
    m_MouseStatus.curMousePosX = xpos;
    m_MouseStatus.curMousePosY = ypos;
}

void GameFPSCameraControl::update() {
    onCameraMoveEvent();
}

/**
 * 处理相机移动事件, 更新相机的位置
 */
void GameFPSCameraControl::onCameraMoveEvent() {
    glm::vec3 direction = glm::vec3(0.f); // 相机移动的方向

    // 计算出当前相机相机的朝向front
    glm::vec3 right = m_Camera->m_Right;
    glm::vec3 front = glm::cross(m_Camera->m_Up, right);

    if (isLeftMove()) {
        direction += right;
    }

    if (isRightMove()) {
        direction -= right;
    }

    if (isBackMove()) {
        direction += front;
    }

    if (isForwardMove()) {
        direction -= front;
    }

    // 判断是否发生了移动
    if (glm::length(direction) != 0.f) {
        // 更新相机坐标
        m_Camera->m_Position += m_CameraMoveSpeed * glm::normalize(direction);
    }
}

/**
 * 处理相机的视角
 * @param dPitch: 上一帧与当前帧pitch的变化
 * @param dYaw: 上一帧与当前帧yaw的变化
 */
void GameFPSCameraControl::onCameraGazeEvent(float dPitch, float dYaw) {
    updatePitch(dPitch);
    updateYaw(dYaw);
}

void GameFPSCameraControl::updatePitch(const float angle) {
    if (m_MouseStatus.isLeftMouseDown) {
        auto rotateMatrix = glm::rotate(glm::mat4(1.0f), glm::radians(-angle), m_Camera->m_Right);
        m_Camera->m_Position = rotateMatrix * glm::vec4(m_Camera->m_Position, 1.0);
        m_Camera->m_Up = rotateMatrix * glm::vec4(m_Camera->m_Up, 0.0);
    } else {
        m_AccPitch += angle;

        if (!isBetweenPitchRange(m_AccPitch)) {
            m_AccPitch -= angle;
            return;
        }

        glm::mat4 rotateMatrix = glm::rotate(glm::mat4(1.f), glm::radians(angle), m_Camera->m_Right);
        m_Camera->m_Up = rotateMatrix * glm::vec4(m_Camera->m_Up, 0.f);
    }
}

void GameFPSCameraControl::updateYaw(const float angle) {
    if (m_MouseStatus.isLeftMouseDown) {
        auto rotateMatrix = glm::rotate(glm::mat4(1.0f), glm::radians(-angle), m_Camera->m_Up);
        m_Camera->m_Position = rotateMatrix * glm::vec4(m_Camera->m_Position, 1.0);
        m_Camera->m_Right = rotateMatrix * glm::vec4(m_Camera->m_Right, 0.0);
        m_Camera->m_Up = rotateMatrix * glm::vec4(m_Camera->m_Up, 0.0);
    } else {
        glm::mat4 rotateMatrix = glm::rotate(glm::mat4(1.f), glm::radians(angle), worldUp);
        m_Camera->m_Right = rotateMatrix * glm::vec4(m_Camera->m_Right, 0.f);
        m_Camera->m_Up = rotateMatrix * glm::vec4(m_Camera->m_Up, 0.f);
    }
}

void GameFPSCameraControl::onScroll(double yoffset) {

}

